package com.lh.jianzhioffer.专项练习.链表;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: linghao
 * @since: 2023/3/18
 *
 * 双向链表+hash表
 *
 * LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
 *  int get(int key) 如果关键字 key 存在于缓存中，则返回关键字的值，否则返回 -1 。
 *  void put(int key, int value) 如果关键字已经存在，则变更其数据值；如果关键字不存在，则插入该组「关键字-值」。当缓存容量达到上限时，它应该在写入新数据之前删除最久未使用的数据值，从而为新的数据值留出空间
 **/
public class 最近最少使用缓存031demo2 {


    private int capacity;
    private int size;
    private Map<Integer,DLinkedNode> cache = new HashMap<>();
    private DLinkedNode head;
    private DLinkedNode tail;

    public 最近最少使用缓存031demo2(int capacity){
        this.size = 0;
        this.capacity = capacity;
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.next = head;
    }

    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if(node == null){
            return -1;
        }
        moveToHead(node);
        return node.val;
    }

    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if(node == null){
            DLinkedNode newNode = new DLinkedNode(key,value);
            addToHead(newNode);
            cache.put(key,newNode);
            size++;
            if(size > capacity){
                //从链表尾部删除
                DLinkedNode removeNode = removeTail();
                cache.remove(removeNode.key);
                size--;
            }
        }else{
            node.val = value;
            moveToHead(node);
        }
    }

    private DLinkedNode removeTail() {
        DLinkedNode node = tail.pre; //需要remove的节点
        removeNode(node);
        return node;
    }

    private void removeNode(DLinkedNode node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

    private void addToHead(DLinkedNode node) {
        node.next = head.next;
        node.pre = head;
        head.next = node;
        node.next.pre = node;
    }

    private void moveToHead(DLinkedNode node) {
        removeNode(node);
        addToHead(node);
    }


    class DLinkedNode{
        int key,val;
        DLinkedNode pre;
        DLinkedNode next;
        public DLinkedNode(){}
        public DLinkedNode(int key,int val){
            this.key = key;
            this.val = val;
        }
    }

}
